using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using FileSystemControls;
using CommonUtilities;
using System.Drawing;

//TODO: WPF Handle: http://stackoverflow.com/questions/10675305/how-to-get-the-hwnd-of-window-instance
//TODO: WidForm Handle: IntPtr hWnd = this.Handle 
//TODO: p/invoke SendMessage: http://www.pinvoke.net/default.aspx/user32.sendmessage

namespace FileTracker
{
    public partial class formMain : Form
    {
        /// <summary>
        /// Delegate for the mapping of Methods to key presses.
        /// </summary>
        public delegate void KeyMethod();

        /// <summary>
        /// Pointer to the source FSLV.
        /// </summary>
        private FileSystemListView _sourceListView;

        /// <summary>
        /// Pointer to the destination FSLV.
        /// </summary>
        private FileSystemListView _destListView;

        /// <summary>
        /// Flag noting whether to ask before deleteing items.
        /// </summary>
        bool _AskBeforeDelete;

        /// <summary>
        /// Pointer to the FileTrackerConfiguration object.
        /// </summary>
        Settings _configSettings;

        /// <summary>
        /// Dictionary Entries for all the key mappings.
        /// </summary>
        Dictionary<Keys, KeyMethod> _localKeyMapping;

        #region ** Constructors, Destructors, and Closing events **

        /// <summary>
        /// Standard constructor.
        /// </summary>
        public formMain()
        {
            {
                //Logger.LogInfo("Form .ctor - begin");

                _localKeyMapping = new Dictionary<Keys, KeyMethod>();

                InitializeComponent();

                fileSystemListViewLeft.PathChanged += new PathChangedEventHandler(FileSystemListView_PathChanged);
                fileSystemListViewRight.PathChanged += new PathChangedEventHandler(FileSystemListView_PathChanged);

                //Add eventdelegate to handle FileSystemListView.OnAddItemProgress
                //This will handle the progress of adding FileItems to the lists.
                fileSystemListViewLeft.AddItemProgress += new AddItemProgressEventHandler(fileSystemListViewLeft_AddItemProgress);
                fileSystemListViewRight.AddItemProgress += new AddItemProgressEventHandler(fileSystemListViewRight_AddItemProgress);

                //Logger.LogInfo("Form .ctor - end");
            }
        }

        /// <summary>
        /// Event handler for tracking the progress of adding FileItems to the Right-hand list view.
        /// </summary>
        /// <param name="sender">Not Used</param>
        /// <param name="e">Not Used</param>
        private void fileSystemListViewRight_AddItemProgress(object sender, AddItemProgressEventArgs e)
        {
            labelItemPercentageRight.Text = e.CurrentPercentage.ToString() + "%";
            labelItemPercentageRight.Refresh();
        }

        /// <summary>
        /// Event handler for tracking the progress of adding FileItems to the Left-hand list view.
        /// </summary>
        /// <param name="sender">Not Used</param>
        /// <param name="e">Not Used</param>
        private void fileSystemListViewLeft_AddItemProgress(object sender, AddItemProgressEventArgs e)
        {
            labelItemPercentageLeft.Text = e.CurrentPercentage.ToString() + "%";
            labelItemPercentageLeft.Refresh();
        }

        /// <summary>
        /// Standard destructor.
        /// </summary>
        ~formMain()
        {
            fileSystemListViewLeft.Dispose();
            fileSystemListViewRight.Dispose();
        }

        /// <summary>
        /// Sets the location and other settings when the main form loads.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void formMain_Load(object sender, EventArgs e)
        {
            Point thisLocation;

            try
            {
                _configSettings = new Settings();

                //Set the mainForm settings
                //Don't put the window size in SetConfiguration because they don't get
                //  set in the Preferences window
                //Don't let the window get put offscreen
                //TODO: 997 - Don't let the window get opened off screen (location - size - 5px)
                this.Size = _configSettings.MainWindowSize;
                thisLocation = _configSettings.MainWindowLocation;

                if (_configSettings.MainWindowLocation.X < (-1*this.Width))
                {
                    thisLocation.X = 0;
                }
                if(_configSettings.MainWindowLocation.X > Screen.PrimaryScreen.WorkingArea.Right)
                {
                    thisLocation.X = 0;
                }

                if(_configSettings.MainWindowLocation.Y < (-1*this.Height))
                {
                    thisLocation.Y = 0;
                }
                if (_configSettings.MainWindowLocation.Y > Screen.PrimaryScreen.WorkingArea.Bottom)
                {
                    thisLocation.Y = 0;
                }
                _configSettings.MainWindowLocation = thisLocation;

                this.Location = _configSettings.MainWindowLocation;
                this.splitContainerMain.SplitterDistance = _configSettings.MainSplitterDistance;

                //Setup the environment from the config file
                SetConfiguration();

                fileSystemListViewLeft.SetPath();
                fileSystemListViewRight.SetPath();
            }
            catch (Exception)
            {
                //Logger.LogInfo("Error in form load\r\n", ex);
            }

        }

        /// <summary>
        /// Saves the location and other settings when the form closes.
        /// </summary>
        /// <param name="sender">Unused.</param>
        /// <param name="e">Unused.</param>
        private void formMain_FormClosing(object sender, FormClosingEventArgs e)
        {

            fileSystemListViewLeft.Dispose();
            fileSystemListViewRight.Dispose();

            _configSettings.MainSplitterDistance = this.splitContainerMain.SplitterDistance;

            //TODO: 997 - Don't let the window get saved off screen (location - size - 5px)
            _configSettings.MainWindowLocation = this.Location;
            _configSettings.MainWindowSize = this.Size;

            _configSettings.Save();
        }

        #endregion

        #region ** FileTrackerConfiguration Methods **

        /// <summary>
        /// Sets the various configurable parameters of the FileSystemListView objects as well as loading other configuration parameters.
        /// </summary>
        private void SetConfiguration()
        {
            try
            {
                fileSystemListViewLeft.SetConfiguration();
                fileSystemListViewRight.SetConfiguration();

                //LoadConfig
                _AskBeforeDelete = _configSettings.AskBeforeDelete;

                //LoadFavorites
                LoadFavorites();

                //LoadOpenWith
                //LoadOpenWith(); //Moved to FileSystemListView.Base

                //LoadDefaultDirectories
                LoadDefaultDirectories();

                //LoadKeys
                LoadKeys();
            }

            catch (Exception ex)
            {
                MessageBox.Show("Error in SetConfiguration: " + ex.Message);
            }
        }

        /// <summary>
        /// Scans the system for drives and fills the dropdown objects with the results.
        /// </summary>
        private void FillDriveBoxes()
        {
            DriveInfo[] allDrives;
            string DriveLabel = String.Empty;

            try
            {
                dropDownButtonLeft.ClearItems();
                dropDownButtonRight.ClearItems();

                // Get a list of the drives in this computer.
                allDrives = DriveInfo.GetDrives();

                foreach (DriveInfo currentDrive in allDrives)
                {
                    if (currentDrive.IsReady)
                    {
                        DriveLabel = currentDrive.Name + " - " + currentDrive.VolumeLabel;
                    }
                    else
                    {
                        DriveLabel = currentDrive.Name + " - Not Ready";
                    }

                    ToolStripMenuItem leftFavorite = new ToolStripMenuItem(DriveLabel, null, Favorite_Click);
                    ToolStripMenuItem rightFavorite = new ToolStripMenuItem(DriveLabel, null, Favorite_Click);

                    leftFavorite.Tag = currentDrive.Name;
                    rightFavorite.Tag = currentDrive.Name;

                    dropDownButtonLeft.AddMenuItem(leftFavorite);
                    dropDownButtonRight.AddMenuItem(rightFavorite);
                }

                dropDownButtonLeft.AddSeparator();
                dropDownButtonRight.AddSeparator();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in FillDriveBoxes: " + ex.Message);
            }
        }

        /// <summary>
        /// Scans the configuration object and adds favorites to the dropdown objects.
        /// </summary>
        private void LoadFavorites()
        {
            string FavoriteName;
            string FavoritePath;

            try
            {
                FillDriveBoxes();

                //Loop through Favorites
                foreach (KeyValuePair<string, string> FavoriteEntry in _configSettings.FavoriteList)
                {
                    ToolStripMenuItem MenuItemFavoriteLeft;
                    ToolStripMenuItem MenuItemFavoriteRight;

                    FavoriteName = FavoriteEntry.Key;
                    FavoritePath = FavoriteEntry.Value;

                    MenuItemFavoriteLeft = new ToolStripMenuItem(FavoriteName, null, Favorite_Click);
                    MenuItemFavoriteRight = new ToolStripMenuItem(FavoriteName, null, Favorite_Click);

                    MenuItemFavoriteLeft.Tag = FavoritePath;
                    MenuItemFavoriteRight.Tag = FavoritePath;

                    dropDownButtonLeft.AddMenuItem(MenuItemFavoriteLeft);
                    dropDownButtonRight.AddMenuItem(MenuItemFavoriteRight);
                }
            }

            catch (Exception ex)
            {
                MessageBox.Show("Error in LoadFavorites: " + ex.Message);
            }
        }


        /// <summary>
        /// Scans the configuration object and adds handlers for any key event that is configured.
        /// </summary>
        private void LoadKeys()
        {
            try
            {
                _localKeyMapping.Clear();

                //Loop through keys
                foreach (KeyValuePair<KeyEnum, Keys> CurrentPair in _configSettings.KeyList)
                {
                    if (CurrentPair.Value != Keys.None)
                    {
                        //Switch based on enum
                        switch (CurrentPair.Key)
                        {
                            //set key to correct method call
                            case KeyEnum.COPY:
                                _localKeyMapping.Add(CurrentPair.Value, CopyItems);
                                break;
                            case KeyEnum.DELETE:
                                _localKeyMapping.Add(CurrentPair.Value, DeleteItem);
                                break;
                            case KeyEnum.MAKEDIR:
                                _localKeyMapping.Add(CurrentPair.Value, MakeDir);
                                break;
                            case KeyEnum.MOVE:
                                _localKeyMapping.Add(CurrentPair.Value, MoveItems);
                                break;
                            case KeyEnum.REFRESH:
                                _localKeyMapping.Add(CurrentPair.Value, RefreshFileList);
                                break;
                            case KeyEnum.RENAME:
                                _localKeyMapping.Add(CurrentPair.Value, RenameItems);
                                break;
                            case KeyEnum.TOUCH:
                                _localKeyMapping.Add(CurrentPair.Value, TouchItem);
                                break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in LoadKeys" + ex.Message);
            }

        }

        /// <summary>
        /// Initializes the FileSystemListViews to their default directories.
        /// </summary>
        private void LoadDefaultDirectories()
        {
            string LeftDefaultFolder;
            string RightDefaultFolder;

            try
            {
                //Load Left pane default directories
                if (_configSettings.LeftDefaultFolderType == FolderType.FavoriteFolder)
                {
                    if (_configSettings.FavoriteList.ContainsKey(_configSettings.LeftDefaultFolder))
                    {
                        LeftDefaultFolder = _configSettings.FavoriteList[_configSettings.LeftDefaultFolder];
                    }
                    else
                    {
                        //Change to "Application root drive"
                        LeftDefaultFolder = new DriveInfo(Application.ExecutablePath).RootDirectory.FullName;
                    }
                }
                else
                {
                    LeftDefaultFolder = _configSettings.LeftDefaultFolder;
                }

                fileSystemListViewLeft.DefaultPath = LeftDefaultFolder;

                //Load Right pane default directories
                if (_configSettings.RightDefaultFolderType == FolderType.FavoriteFolder)
                {
                    if (_configSettings.FavoriteList.ContainsKey(_configSettings.RightDefaultFolder))
                    {
                        RightDefaultFolder = _configSettings.FavoriteList[_configSettings.RightDefaultFolder];
                    }
                    else
                    {
                        //Change to "Application root drive"
                        RightDefaultFolder = new DriveInfo(Application.ExecutablePath).RootDirectory.FullName;
                    }
                }
                else
                {
                    RightDefaultFolder = _configSettings.RightDefaultFolder;
                }

                fileSystemListViewRight.DefaultPath = RightDefaultFolder;

            }

            catch (Exception ex)
            {
                MessageBox.Show("Error in LoadDefaultDirectories" + ex.Message);
            }
        }

        #endregion

        #region ** Favorites Methods **

        /// <summary>
        /// Looks for which item was clicked and sets the current directory to that favorite.
        /// </summary>
        /// <param name="sender">The ToolStripDropDownItem object that raised this event.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void Favorite_Click(object sender, EventArgs e)
        {
            try
            {
                ToolStripDropDownItem ClickedItem;

                ClickedItem = (ToolStripDropDownItem)sender;

                //Find the FileSystemListView associated with this DropDown button.
                string ViewSide = (string)ClickedItem.Owner.Tag;

                if (ViewSide == "Left")
                {
                    _sourceListView = fileSystemListViewLeft;
                    _destListView = fileSystemListViewRight;
                }
                else
                {
                    _sourceListView = fileSystemListViewRight;
                    _destListView = fileSystemListViewLeft;
                }

                _sourceListView.SetPath((string)ClickedItem.Tag);
            }

            catch (Exception ex)
            {
                MessageBox.Show("Error in Favorite_Click" + ex.Message);
            }
        }

        /// <summary>
        /// Opens the "Add MenuItemFavoriteLeft" dialog box.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void toolStripMenuItemAddFavorite_Click(object sender, EventArgs e)
        {
            try
            {
                FormAddFavorite addFavoriteForm;

                //Code to add favorites
                addFavoriteForm = new FormAddFavorite();
                addFavoriteForm.CurrentPath = _sourceListView.CurrentPath;

                addFavoriteForm.ShowDialog(this);

                _configSettings.Reload();

                LoadFavorites();
                //SetFavoriteName(_sourceListView);
            }

            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripMenuItemAddFavorite_Click " + ex.Message);
            }
        }

        /// <summary>
        /// Opens the "Edit Favorites" dialog box.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void toolStripMenuItemEditFavorites_Click(object sender, EventArgs e)
        {
            //Code to edit favorites
            FormEditFavorites editFavoriteForm;

            try
            {
                //Code to add favorites
                editFavoriteForm = new FormEditFavorites();
                editFavoriteForm.ShowDialog(this);

                editFavoriteForm = null;

                _configSettings.Reload();

                LoadFavorites();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripMenuItemEditFavorites_Click" + ex.Message);
            }
        }

        #endregion

        #region ** OpenWith Methods **


        /// <summary>
        /// Add programs to the "Open With" sub-menu.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void toolStripMenuItemAddOpenWith_Click(object sender, EventArgs e)
        {
            try
            {
                FormAddOpenWith addOpenWithForm;

                //Code to add OpenWith
                addOpenWithForm = new FormAddOpenWith();

                addOpenWithForm.ShowDialog(this);

                _configSettings.Reload();
                fileSystemListViewLeft.LoadOpenWith(_configSettings);
                fileSystemListViewRight.LoadOpenWith(_configSettings);

            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripMenuItemAddOpenWith_Click " + ex.Message);
            }
        }

        /// <summary>
        /// Edit the list of programs offered in the "Open With" sub-menu.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void toolStripMenuItemEditOpenWith_Click(object sender, EventArgs e)
        {
            //Edit OpenWith
            FormEditOpenWith editOpenWithForm;

            try
            {
                //Code to add favorites
                editOpenWithForm = new FormEditOpenWith();
                editOpenWithForm.ShowDialog(this);

                editOpenWithForm = null;

                _configSettings.Reload();

                fileSystemListViewLeft.LoadOpenWith(_configSettings);
                fileSystemListViewRight.LoadOpenWith(_configSettings);

            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripMenuItemEditOpenWith_Click" + ex.Message);
            }
        }

        #endregion

        #region ** Toolstrip Button Methods **

        /// <summary>
        /// Stubs out the RefreshFileList method.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void toolStripButtonRefresh_Click(object sender, EventArgs e)
        {
            //This allows me to use the FileTrackerConfiguration.KeyMethod delegate
            //  for all the method calls rather than being forced to pass
            //  not needed arguments.
            RefreshFileList();
        }

        /// <summary>
        /// Stubs out the CopyItem method.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void toolStripButtonCopy_Click(object sender, EventArgs e)
        {
            //This allows me to use the FileTrackerConfiguration.KeyMethod delegate
            //  for all the method calls rather than being forced to pass
            //  not needed arguments.
            CopyItems();
        }

        /// <summary>
        /// Stubs out the MoveItems method.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void toolStripButtonMove_Click(object sender, EventArgs e)
        {
            //This allows me to use the FileTrackerConfiguration.KeyMethod delegate
            //  for all the method calls rather than being forced to pass
            //  not needed arguments.
            MoveItems();
        }

        /// <summary>
        /// Stubs out the MakeDir method.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void toolStripButtonMakeDir_Click(object sender, EventArgs e)
        {
            //This allows me to use the FileTrackerConfiguration.KeyMethod delegate
            //  for all the method calls rather than being forced to pass
            //  not needed arguments.
            MakeDir();
        }

        /// <summary>
        /// Stubs out the DeleteItem method.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void toolStripButtonDelete_Click(object sender, EventArgs e)
        {
            DeleteItem();
        }

        /// <summary>
        /// Sets the right drectory to the left directory's path.
        /// </summary>
        /// <param name="sender">The object raising the event. Unused.</param>
        /// <param name="e">The event agruments object. Unused.</param>
        private void toolStripButtonSyncPathLeft_Click(object sender, EventArgs e)
        {
            try
            {
                fileSystemListViewRight.SetPath(fileSystemListViewLeft.CurrentPath);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripButtonSyncPathLeft_Click" + ex.Message);
            }
        }

        /// <summary>
        /// Sets the left drectory to the right directory's path.
        /// </summary>
        /// <param name="sender">The object raising the event. Unused.</param>
        /// <param name="e">The event agruments object. Unused.</param>
        private void toolStripButtonSyncPathRight_Click(object sender, EventArgs e)
        {
            try
            {
                fileSystemListViewLeft.SetPath(fileSystemListViewRight.CurrentPath);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripButtonSyncPathRight_Click" + ex.Message);
            }
        }

        /// <summary>
        /// Copies each directory's content into the other directory.
        /// </summary>
        /// <param name="sender">The object raising the event. Unused.</param>
        /// <param name="e">The event agruments object. Unused.</param>
        private void toolStripButtonSynchDir_Click(object sender, EventArgs e)
        {
            //Synch left dir into the right
            //Get a list of FileList in LeftDir
            DirectoryInfo LeftDirInfo = new DirectoryInfo(fileSystemListViewLeft.CurrentPath);

            //Get a list of FileList in RightDir
            DirectoryInfo RightDirInfo = new DirectoryInfo(fileSystemListViewRight.CurrentPath);

            SyncDirs(LeftDirInfo, RightDirInfo);

            fileSystemListViewLeft.RefreshPath();
            fileSystemListViewRight.RefreshPath();

        }

        /// <summary>
        /// Synchronizes two paths to contain the same files and directories.
        /// </summary>
        /// <param name="LeftDirInfo"></param>
        /// <param name="RightDirInfo"></param>
        private void SyncDirs(DirectoryInfo LeftDirInfo, DirectoryInfo RightDirInfo)
        {
            try
            {
                FileInfo[] LeftFileList = LeftDirInfo.GetFiles();
                FileInfo[] RightFileList = RightDirInfo.GetFiles();

                //Ask if this is really what the user intends
                DialogResult SyncResult = MessageBox.Show(this, "This operation will synchronise the contents " +
                    "of both directories ('" + fileSystemListViewLeft.CurrentPath + "' and '" +
                    fileSystemListViewRight.CurrentPath + "'). This may take a considerable amount of time and " +
                    "may destroy data (if it is duplicated in both places). Are you sure you want to do this?",
                    "Verify Sync Operation", MessageBoxButtons.YesNo, MessageBoxIcon.Warning,
                    MessageBoxDefaultButton.Button2);

                if (SyncResult == DialogResult.No)
                {
                    return;
                }

                //Loop through FileList in LeftDir
                foreach (FileInfo LeftFile in LeftFileList)
                {
                    //  Find item in RightDir
                    FileInfo TempRightFile = new FileInfo(RightDirInfo.FullName + "\\" + LeftFile.Name);

                    //  if found, compare
                    if (TempRightFile.Exists)
                    {
                        //  if found, compare dates
                        if (TempRightFile.LastWriteTime < LeftFile.LastWriteTime)
                        {
                            //      if RightDir.Date < LeftDir.Date, copy
                            TempRightFile.IsReadOnly = false;
                            LeftFile.CopyTo(TempRightFile.FullName, true);
                        }
                    }
                    else //if not found, copy
                    { //TempRightFile.FullName
                        LeftFile.CopyTo(TempRightFile.FullName);
                    }
                }

                //Loop through FileList in RightDir
                foreach (FileInfo RightFile in RightFileList)
                {
                    //  Find item in LeftDir
                    FileInfo TempLeftFile = new FileInfo(LeftDirInfo.FullName + "\\" + RightFile.Name);

                    //  if found, compare
                    if (TempLeftFile.Exists)
                    {
                        //  if found, compare dates
                        if (TempLeftFile.LastWriteTime < RightFile.LastWriteTime)
                        {
                            //      if LeftDir.Date < RightDir.Date, copy
                            TempLeftFile.IsReadOnly = false;
                            RightFile.CopyTo(TempLeftFile.FullName, true);
                        }

                    }
                    else //if not found, copy
                    {
                        RightFile.CopyTo(TempLeftFile.FullName);
                    }
                }

                //Now sync directories.
                DirectoryInfo[] LeftDirList = LeftDirInfo.GetDirectories();

                foreach (DirectoryInfo LeftDir in LeftDirList)
                {
                    DirectoryInfo RightTempDir = new DirectoryInfo(RightDirInfo.FullName + "\\" + LeftDir.Name);
                    if (!RightTempDir.Exists)
                    {
                        RightTempDir = Directory.CreateDirectory(RightDirInfo.FullName + "\\" + LeftDir.Name);
                    }

                    SyncDirs(LeftDir, RightTempDir);
                }

                DirectoryInfo[] RightDirList = RightDirInfo.GetDirectories();
                foreach (DirectoryInfo RightDir in RightDirList)
                {
                    DirectoryInfo LeftTempDir = new DirectoryInfo(LeftDirInfo.FullName + "\\" + RightDir.Name);
                    if (!LeftTempDir.Exists)
                    {
                        LeftTempDir = Directory.CreateDirectory(LeftDirInfo.FullName + "\\" + RightDir.Name);
                    }

                    SyncDirs(RightDir, LeftTempDir);
                }


            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripButtonSynchDir_Click" + ex.Message);
            }

        }

        /// <summary>
        /// Updates "Modified Date" on the selected files.
        /// </summary>
        /// <param name="sender">Unused</param>
        /// <param name="e">Unused</param>
        private void toolStripButtonTouch_Click(object sender, EventArgs e)
        {
            //This allows me to use the FileTrackerConfiguration.KeyMethod delegate
            //  for all the method calls rather than being forced to pass
            //  not needed arguments.
            TouchItem();
        }

        /// <summary>
        /// Fires appropriate method for key bindings.
        /// </summary>
        /// <param name="sender">Unused</param>
        /// <param name="e">Unused</param>
        private void autoSizeTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Enter:
                    NavigatePath((AutoSizeTextBox)sender);
                    e.Handled = true;
                    break;
                default:
                    e.Handled = false;
                    break;
            }
        }

        #endregion

        #region ** Menuitem Methods **

        /// <summary>
        /// Executed when the user clicks the "Exit" menu item.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object. Unused.</param>
        private void toolStripMenuItemExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Opens the About box
        /// </summary>
        /// <param name="sender">Unused</param>
        /// <param name="e">Unused</param>
        private void toolStripMenuItemAbout_Click(object sender, EventArgs e)
        {
            AboutBoxFileTracker AboutBox;

            AboutBox = new AboutBoxFileTracker();

            AboutBox.ShowDialog();
        }

        /// <summary>
        /// For internal use only.
        /// </summary>
        /// <param name="sender">Unused</param>
        /// <param name="e">Unused</param>
        private void toolStripMenuItemInfo_Click(object sender, EventArgs e)
        {
            //MessageBox.Show("Splitter position: " + splitterMain.Left.ToString() );
            //MessageBox.Show("Main Window Length: " + this.Length.ToString());
            //MessageBox.Show("Name column: " + fileSystemListViewLeft.Columns[0].Width.ToString());
            //MessageBox.Show("Length column: " + fileSystemListViewLeft.Columns[1].Width.ToString());
            //MessageBox.Show("Date column: " + fileSystemListViewLeft.Columns[2].Width.ToString());
        }

        /// <summary>
        /// Opens the "Preferences" window.
        /// </summary>
        /// <param name="sender">Unused</param>
        /// <param name="e">Unused</param>
        private void toolStripMenuItemPreferences_Click(object sender, EventArgs e)
        {
            FormPreferences formPreferences;

            formPreferences = new FormPreferences();

            _configSettings.Reload();

            formPreferences.Location = _configSettings.PreferenceWindowLocation;
            formPreferences.Size = _configSettings.PreferenceWindowSize;
            formPreferences.SplitterDistance = _configSettings.PreferencesSplitterDistance;

            formPreferences.ShowDialog(this);

            formPreferences.Dispose();
            formPreferences = null;

            _configSettings.Reload();

            SetConfiguration();
        }

        #endregion

        #region ** Event Handlers **

        /// <summary>
        /// Executed when the user presses a key on the keyboard.
        /// </summary>
        /// <param name="sender">The object raising this event. Unused.</param>
        /// <param name="e">The event arguments object containing data regarding the key that was pressed.</param>
        private void formMain_KeyDown(object sender, KeyEventArgs e)
        {

            //MessageBox.Show("Sender: " + sender.ToString());

            if (_localKeyMapping.ContainsKey(e.KeyCode))
            {
                KeyMethod CallingMethod = _localKeyMapping[e.KeyCode];
                CallingMethod.Invoke();
            }
            else
            {
                //Console.WriteLine("KeyCode: " + e.KeyCode);
                //Console.WriteLine("KeyData: " + e.KeyData);
                e.SuppressKeyPress = false;
                e.Handled = false;
            }

        }

        /// <summary>
        /// Executed when Windows has a message. Used to trap the Device Changed message and rescan the drives on the computer.
        /// </summary>
        /// <param name="m">The message recieved.</param>
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            //If a device was inserted refresh the drives and favorites
            //I don't need to keep such a close eye on what was added and where,
            //just do a scan and pickup what's here now.
            if (m.Msg == (int)WindowsMessages.WM_DEVICECHANGE)
            {
                //TODO: 998 - add code to poll devices and find WindowsMedia Devices
                LoadFavorites();
            }
        }

        /// <summary>
        /// Occurs when the user hits "Enter" in the AutoSizeTextBox.
        /// </summary>
        /// <param name="sender">The AutoSizeTextBox that fired the event.</param>
        private void NavigatePath(AutoSizeTextBox sender)
        {
            AutoSizeTextBox currentTextBox;

            try
            {
                ////Get the ComboBox that sent the message
                currentTextBox = (AutoSizeTextBox)sender;
                if (currentTextBox.Text == "")
                    return;

                //Set the directory in the ListView
                _sourceListView = (FileSystemListView)currentTextBox.Parent.Parent.Controls[0];

                if (_sourceListView == fileSystemListViewLeft)
                {
                    _destListView = fileSystemListViewRight;
                }
                else
                {
                    _destListView = fileSystemListViewLeft;
                }
                currentTextBox.Text = currentTextBox.Text.Trim();

                _sourceListView.SetPath(currentTextBox.Text);
            }
            catch (Exception ex)
            {
                _sourceListView.Cursor = Cursors.Default;
                MessageBox.Show("Error in NavigatePath: " + ex.Message);
            }
        }

        /// <summary>
        /// Changes the source (Left) and destination (Right) objects.
        /// </summary>
        /// <param name="sender">Unused.</param>
        /// <param name="e">Unused.</param>
        private void fileSystemListViewLeft_Enter(object sender, EventArgs e)
        {
            _sourceListView = fileSystemListViewLeft;
            _destListView = fileSystemListViewRight;
        }

        /// <summary>
        /// Changes the source (Right) and destination (Left) objects.
        /// </summary>
        /// <param name="sender">Unused.</param>
        /// <param name="e">Unused.</param>
        private void fileSystemListViewRight_Enter(object sender, EventArgs e)
        {
            _sourceListView = fileSystemListViewRight;
            _destListView = fileSystemListViewLeft;
        }

        /// <summary>
        /// Resets the controls when the path in the FSLV changes.
        /// </summary>
        /// <param name="sender">FSLV object that raised the event.</param>
        /// <param name="e">Event arguments that hold the new path.</param>
        private void FileSystemListView_PathChanged(object sender, FileSystemPathChangedEventArgs e)
        {
            string ViewSide;
            FlowLayoutPanel CurrentFlowPanel;
            DropDownButton CurrentFavoritesDropDown;
            TextBox CurrentPathTextBox;

            try
            {
                FileSystemListView CurrentView = (FileSystemListView)sender;
                ViewSide = (string)CurrentView.Tag;
                if (ViewSide == "Left")
                {
                    CurrentFlowPanel = flowLayoutPanelLeft;
                    CurrentFavoritesDropDown = dropDownButtonLeft; //buttonFavoritesLeft;//dropDownButtonFavoritesLeft;
                    CurrentPathTextBox = autoSizeTextBoxLeft;
                }
                else
                {
                    CurrentFlowPanel = flowLayoutPanelRight;
                    CurrentFavoritesDropDown = dropDownButtonRight; //buttonFavoritesRight;//dropDownButtonFavoritesRight;
                    CurrentPathTextBox = autoSizeTextBoxRight;
                }

                CurrentPathTextBox.Text = e.NewPath;
                CurrentFavoritesDropDown.SetFavorite(e.NewPath);

                //Set the "Free Space" if possible
                Label CurrentFreespaceLabel = (Label)CurrentFlowPanel.Controls["labelFreeSpace" + ViewSide];

                CurrentFreespaceLabel.Text = CurrentView.AvailableFreeSpaceText;

                CurrentView.Focus();

            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in FileSystemListView_PathChanged - " + ex.Message);
            }
        }

        /// <summary>
        /// Activate the form and control if the user tries to drag something over the controls (in preperation for the Drop event).
        /// </summary>
        /// <param name="sender">Unused.</param>
        /// <param name="e">unused.</param>
        private void fileSystemListView_DragEnter(object sender, DragEventArgs e)
        {
            //Bring form to the front
            this.Activate();
            this.BringToFront();
        }

        /// <summary>
        /// Refresh the FSLV after the drop action.
        /// </summary>
        /// <param name="sender">Unused.</param>
        /// <param name="e">Unused.</param>
        private void fileSystemListView_DragDrop(object sender, DragEventArgs e)
        {
            fileSystemListViewLeft.RefreshPath();
            fileSystemListViewRight.RefreshPath();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonFilterLeft_Click(object sender, EventArgs e)
        {
            if (!comboBoxNameFilterLeft.Items.Contains(comboBoxNameFilterLeft.Text))
            {
                comboBoxNameFilterLeft.Items.Add(comboBoxNameFilterLeft.Text);
            }

            fileSystemListViewLeft.NameFilter = comboBoxNameFilterLeft.Text;
            fileSystemListViewLeft.ExtFilter = comboBoxExtFilterLeft.Text;
            fileSystemListViewLeft.RefreshPath();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonFilterRight_Click(object sender, EventArgs e)
        {
            if (!comboBoxNameFilterRight.Items.Contains(comboBoxNameFilterRight.Text))
            {
                comboBoxNameFilterRight.Items.Add(comboBoxNameFilterRight.Text);
            }

            fileSystemListViewRight.NameFilter = comboBoxNameFilterRight.Text;
            fileSystemListViewRight.ExtFilter = comboBoxExtFilterRight.Text;
            fileSystemListViewRight.RefreshPath();
        }

        private void buttonFilterResetLeft_Click(object sender, EventArgs e)
        {
            comboBoxNameFilterLeft.Text = "*";
            comboBoxExtFilterLeft.Text = "*";
            fileSystemListViewLeft.NameFilter = "*";
            fileSystemListViewLeft.ExtFilter = "*";
            fileSystemListViewLeft.RefreshPath();

        }

        private void buttonFilterResetRight_Click(object sender, EventArgs e)
        {
            comboBoxNameFilterRight.Text = "*";
            comboBoxExtFilterRight.Text = "*";
            fileSystemListViewRight.NameFilter = "*";
            fileSystemListViewRight.ExtFilter = "*";
            fileSystemListViewRight.RefreshPath();

        }

        #endregion

        #region ** Private Methods **


        /// <summary>
        /// Refreshes the file and directory list on the currently active FileSystemListView.
        /// </summary>
        private void RefreshFileList()
        {
            try
            {
                _sourceListView.RefreshPath();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripButtonRefresh_Click" + ex.Message);
            }
        }

        /// <summary>
        /// Copies the list of selected FileList and directories from the currently active FileSystemListView to the other.
        /// </summary>
        private void CopyItems()
        {

            try
            {
                if (_sourceListView.SelectedItems.Count <= 0)
                {
                    MessageBox.Show("No items selected.");
                    return;
                }

                if (_sourceListView.CurrentPath == _destListView.CurrentPath)
                {
                    MessageBox.Show("Source and Destination Directories can't be the same. Try Duplicate instead.", "Copying Items");
                    return;
                }

                try
                {
                    Cursor = Cursors.WaitCursor;

                    FormCopyProgress CopyForm = new FormCopyProgress();

                    CopyForm.SelectedItems = _sourceListView.SelectedItems;
                    CopyForm.DestinationPath = _destListView.CurrentPath;

                    CopyForm.ShowDialog(this);

                    _sourceListView.RefreshPath();
                    _destListView.RefreshPath();

                }
                catch (IOException)
                {
                    MessageBox.Show("Unable to copy file.  Check permissions, destination file is not in use, or drive is not full.");
                }
                catch (Exception ex)
                {
                    //Messagebox telling the user that we encountered an error and may not have finished copying the file.
                    MessageBox.Show("Unexpected Exception:" + ex.Message + "\r\nFile was not copied correctly.");
                    return;
                }
            }

            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripButtonCopy_Click" + ex.Message);
            }
            finally
            {
                Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// Moves the list of selected FileList and directories from the currently active FileSystemListView to the other.
        /// </summary>
        private void MoveItems()
        {
            FormYesNoYestoall MessageForm = new FormYesNoYestoall();
            DialogResultEx moveFileResult;
            bool ForceAction = !_AskBeforeDelete; //If I do "ask" I don't "force"

            if (_sourceListView.CurrentPath == _destListView.CurrentPath)
            {
                MessageBox.Show("Source and Destination can't be the same.", "Moving Items");
                return;
            }

            if (_sourceListView.SelectedItems.Count <= 0)
            {
                MessageBox.Show("No items selected.");
                return;
            }

            try
            {

                Cursor = Cursors.WaitCursor;

                //fileSystemListViewLeft.SuspendWatching();
                //fileSystemListViewRight.SuspendWatching();

                //Move FileList or folders
                foreach (FileListViewItem CurrentListViewItem in _sourceListView.SelectedFileItems)
                {
                    if (CurrentListViewItem.IsOffline)
                    {
                        MessageBox.Show("File " + CurrentListViewItem.Name + " is offline. You cannot move it.", "Move File");
                        return;
                    }

                    if (CurrentListViewItem.IsReadOnly && !ForceAction)
                    {
                        MessageForm.ShowDialog("File " + CurrentListViewItem.Name + " is read-only.  Do you still want to move it?", "Move File");
                        moveFileResult = MessageForm.DialogResultEx;

                        if (moveFileResult == DialogResultEx.No)
                            return;

                        if (moveFileResult == DialogResultEx.YesToAll)
                        {
                            ForceAction = true;
                        }
                    }

                    if (CurrentListViewItem.IsSystem && !ForceAction)
                    {
                        MessageForm.ShowDialog("File " + CurrentListViewItem.Name + " is a system file. Are you sure you still want to move it?", "Move File");
                        moveFileResult = MessageForm.DialogResultEx;

                        if (moveFileResult == DialogResultEx.No)
                            return;

                        if (moveFileResult == DialogResultEx.YesToAll)
                        {
                            ForceAction = true;
                        }
                    }

                    FileInfo DestFile = new FileInfo(_destListView.CurrentPath + "\\" + CurrentListViewItem.Name);
                    //If exists check read-only
                    if (DestFile.Exists && !ForceAction)
                    {
                        MessageForm.ShowDialog("Destination file already exists with that name (" + DestFile.Name + ").  Do you want to overwrite it?", "Move File");
                        moveFileResult = MessageForm.DialogResultEx;

                        if (moveFileResult == DialogResultEx.No)
                            return;

                        if (moveFileResult == DialogResultEx.YesToAll)
                        {
                            ForceAction = true;
                        }

                        if (DestFile.IsReadOnly && !ForceAction)
                        {
                            MessageForm.ShowDialog("Destination file " + DestFile.Name + " is read-only.  Do you want to overwrite it?", "Move File");
                            moveFileResult = MessageForm.DialogResultEx;

                            if (moveFileResult == DialogResultEx.No)
                                return;

                            if (moveFileResult == DialogResultEx.YesToAll)
                            {
                                ForceAction = true;
                            }
                        }
                    }

                    CurrentListViewItem.MoveTo(_destListView.CurrentPath, true);

                }

                foreach (DirectoryListViewItem CurrentListViewItem in _sourceListView.SelectedDirectoryItems)
                {
                    //If it's a directory then move it (FileManager doesn't check for ReadOnly subFiles so I won't either)
                    CurrentListViewItem.MoveTo(_destListView.CurrentPath);
                }

                //fileSystemListViewLeft.ResumeWatching();
                //fileSystemListViewRight.ResumeWatching();

                fileSystemListViewLeft.RefreshPath();
                fileSystemListViewRight.RefreshPath();
            }

            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripButtonMove_Click" + ex.Message);
            }
            finally
            {
                Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// Creates a directory in the current FileSystemListView path using the user-supplied name.
        /// </summary>
        private void MakeDir()
        {
            //Code to Make a directory in the current directory
            FormMakeDir MakeDir;

            try
            {
                MakeDir = new FormMakeDir(_sourceListView.CurrentPath);
                //_sourceListView.SuspendWatching();

                MakeDir.ShowDialog(this);

                //_sourceListView.ResumeWatching();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripButtonMakeDir_Click" + ex.Message);
            }
        }

        /// <summary>
        /// Delete a directory or file.
        /// </summary>
        private void DeleteItem()
        {
            FormYesNoYestoall MessageForm = new FormYesNoYestoall();
            DialogResultEx VerifyDeleteResult = DialogResultEx.Yes;
            bool YesToAll = !_AskBeforeDelete;
            bool ForceDelete = false;

            if (_sourceListView.SelectedItems.Count <= 0)
            {
                MessageBox.Show("No items selected.");
                return;
            }

            try
            {
                Cursor = Cursors.WaitCursor;

                //_sourceListView.SuspendWatching();
                //Code to delete FileList or folders
                foreach (FileListViewItem CurrentListViewItem in _sourceListView.SelectedFileItems)
                {
                    if (!YesToAll)
                    {
                        MessageForm.ShowDialog("Are you sure you want to delete " + CurrentListViewItem.Name, "Delete Confirmation");
                        VerifyDeleteResult = MessageForm.DialogResultEx;
                        if (VerifyDeleteResult == DialogResultEx.No)
                        {
                            continue;
                        }

                        if (VerifyDeleteResult == DialogResultEx.Yes)
                        {
                            ForceDelete = true;
                        }

                        if (VerifyDeleteResult == DialogResultEx.YesToAll)
                        {
                            YesToAll = true;
                            ForceDelete = true;
                        }

                        if (CurrentListViewItem.IsSystem && !YesToAll)
                        {
                            MessageForm.ShowDialog(CurrentListViewItem.Name + " is a system file.  Are you sure you want to delete it?", "Confirm Delete");
                            VerifyDeleteResult = MessageForm.DialogResultEx;
                            if (VerifyDeleteResult == DialogResultEx.No)
                            {
                                continue;
                            }

                            if (VerifyDeleteResult == DialogResultEx.Yes)
                            {
                                ForceDelete = true;
                            }

                            if (VerifyDeleteResult == DialogResultEx.YesToAll)
                            {
                                YesToAll = true;
                                ForceDelete = true;
                            }
                        }

                        if (CurrentListViewItem.IsReadOnly && !YesToAll)
                        {
                            MessageForm.ShowDialog(CurrentListViewItem.Name + " is a read-only file.  Are you sure you want to delete it?", "Confirm Delete");
                            VerifyDeleteResult = MessageForm.DialogResultEx;
                            if (VerifyDeleteResult == DialogResultEx.No)
                            {
                                continue;
                            }

                            if (VerifyDeleteResult == DialogResultEx.Yes)
                            {
                                ForceDelete = true;
                            }

                            if (VerifyDeleteResult == DialogResultEx.YesToAll)
                            {
                                YesToAll = true;
                                ForceDelete = true;
                            }
                        }

                        if (CurrentListViewItem.IsOffline && !YesToAll)
                        {
                            MessageBox.Show(CurrentListViewItem.Name + " is currently offline.  Cannot delete at this time.", "Cannot Delete File");
                        }
                    } //end if confirm delete

                    CurrentListViewItem.Delete(ForceDelete);

                }

                foreach (DirectoryListViewItem CurrentListViewItem in _sourceListView.SelectedDirectoryItems)
                {
                    if (_destListView.CurrentPath == CurrentListViewItem.Path)
                    {
                        _destListView.SetPath(CurrentListViewItem.ParentDirectory);
                    }

                    try
                    {
                        if (_AskBeforeDelete)
                        {
                            DialogResult DirectoryDelete;
                            DirectoryDelete = MessageBox.Show("Are you sure you want to delete " + CurrentListViewItem.Name + " and all it's subdirectories?", "Confirm Delete", MessageBoxButtons.YesNo);

                            if (DirectoryDelete == DialogResult.No)
                            {
                                continue;
                            }

                            CurrentListViewItem.Delete(!_AskBeforeDelete);
                        }
                    }
                    catch (FileIsReadOnlyException ReadonlyException)
                    {
                        FileInfo ReadonlyFile = ReadonlyException.ReadonlyFile;
                        MessageForm.ShowDialog("File " + ReadonlyFile.Name + " is ReadOnly. Are you sure you want to delete it?", "Delete ReadOnly File");
                        DialogResultEx DeleteResult = MessageForm.DialogResultEx;
                        if (DeleteResult == DialogResultEx.Yes)
                        {
                            ReadonlyFile.IsReadOnly = false;
                            ReadonlyFile.Delete();
                            DeleteItem();
                        }
                        if (DeleteResult == DialogResultEx.YesToAll)
                        {
                            CurrentListViewItem.Delete(true);
                        }
                    }
                }//End Foreach
                //_sourceListView.ResumeWatching();

            }

            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripButtonDelete_Click" + ex.Message);
            }
            finally
            {
                _sourceListView.RefreshPath();
                //_destListView.RefreshPath();
                Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// Opens the "Rename Item" form.
        /// </summary>
        public void RenameItems()
        {
            _sourceListView.RenameItems();
        }

        /// <summary>
        /// Updates the "Modified Date" on the selected files.
        /// </summary>
        private void TouchItem()
        {
            if (_sourceListView.SelectedFileItems.Count <= 0)
            {
                MessageBox.Show("No FileList selected.");
                return;
            }

            try
            {
                //Loop through the selected FileList
                foreach (FileListViewItem CurrentItem in _sourceListView.SelectedFileItems)
                {
                    CurrentItem.Touch();
                }

                _sourceListView.RefreshPath();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error in toolStripButtonTouch_Click" + ex.Message);
            }
        }


        #endregion

        private void filterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (filterToolStripMenuItem.Checked)
            {
                flowLayoutPanelFilterLeft.Height = 35;
                flowLayoutPanelFilterLeft.AutoSize = true;

                flowLayoutPanelFilterRight.Height = 35;
                flowLayoutPanelFilterRight.AutoSize = true;
            }
            else
            {
                flowLayoutPanelFilterLeft.AutoSize = false;
                flowLayoutPanelFilterLeft.Height = 1;

                flowLayoutPanelFilterRight.AutoSize = false;
                flowLayoutPanelFilterRight.Height = 1;
            }
        }

        private void flowLayoutPanelAddressLeft_Layout(object sender, LayoutEventArgs e)
        {
            autoSizeTextBoxLeft.ResizeTextBox();
        }

        private void flowLayoutPanelAddressRight_Layout(object sender, LayoutEventArgs e)
        {
            autoSizeTextBoxRight.ResizeTextBox();
        }

        private void buttonRename_Click(object sender, EventArgs e)
        {
            RenameItems();
        }

        private void buttonModifyDate_Click(object sender, EventArgs e)
        {

            FormModifyDate ModifyForm = new FormModifyDate(_sourceListView.SelectedFileItems);
            ModifyForm.ShowDialog(this);
            _sourceListView.RefreshPath();
        }

    }
}